package DAO;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;

import oracle.jdbc.OracleTypes;
import utils.MetaDataUtils;

import BD.ErreurSQL;
import Bean.Profil;

/**
 * @author Romain Agniel
 *
 */

public class ProfilDAO
{
	private Connection conn;
	
	/** Constructeur de la classe ProfilDAO
	 * 
	 * @param conn
	 */
	public ProfilDAO(Connection conn)
	{
		this.conn = conn;
	}
	
	/** Method qui renvoie la liste des profils
	 * @throws SQLException 
	 * 
	 */
	public ArrayList<Profil> getListeProfils() throws ErreurSQL
	{
		ArrayList<Profil> liste = new ArrayList<Profil>();
		
		Statement stmt;
		
		try
		{
			stmt = this.conn.createStatement();
		
			ResultSet resultat = stmt.executeQuery("SELECT * FROM licpro.profil");
		
			while (resultat.next())
			{
				String refer = resultat.getString("refer");
				String description = resultat.getString("description");
				int hauteur = resultat.getInt("hauteur");
				int longueur = resultat.getInt("longueur");
				int cdpx = resultat.getInt("cdpx");
				int cdpy = resultat.getInt("cdpy");
				double er = resultat.getDouble("er");
				double alpha = resultat.getDouble("alpha");
				double cz = resultat.getDouble("cz");
				double cx = resultat.getDouble("cx");
				Profil p = new Profil(refer,description,hauteur,longueur,cdpx,cdpy,er,alpha,cz,cx);
				liste.add(p);
				p.toString();
			}
			
			return liste;
		
		} 
		
		catch (SQLException e)
		{
			throw new ErreurSQL(e.getErrorCode(), e.getMessage());
		}
	}
	
	/** Methode qui apelle une procédure stockée
	 * Cette méthode permet de récupérer une liste de profils 
	 * @throws ErreurSQL 
	 * 
	 */
	public ArrayList<Profil> getListProfilsWithProcedure() throws ErreurSQL
	{
		try
		{
			ArrayList<Profil> liste = new ArrayList<Profil>();
			CallableStatement cs =  this.conn.prepareCall("call licpro.aeronautique.liste_profil(?)");
			cs.registerOutParameter(1, OracleTypes.CURSOR);
			cs.execute();
			ResultSet resultat = (ResultSet) cs.getObject(1);
			
			while (resultat.next())
			{
				String refer = resultat.getString("refer");
				String description = resultat.getString("description");
				int hauteur = resultat.getInt("hauteur");
				int longueur = resultat.getInt("longueur");
				int cdpx = resultat.getInt("cdpx");
				int cdpy = resultat.getInt("cdpy");
				double er = resultat.getDouble("er");
				double alpha = resultat.getDouble("alpha");
				double cz = resultat.getDouble("cz");
				double cx = resultat.getDouble("cx");
				Profil p = new Profil(refer,description,hauteur,longueur,cdpx,cdpy,er,alpha,cz,cx);
				liste.add(p);
				p.toString();
			}
			
			return liste;

		}
		
		catch (SQLException e)
		{
			throw new ErreurSQL(e.getErrorCode(), e.getMessage());
		}
	}
	
	/** Methode qui permet de rechercher un profil
	 * @param refer la référence au profil recherché
	 * @throws ErreurSQL
	 */
	public ArrayList<Profil> searchProfil(String refer) throws ErreurSQL
	{
		try
		{
			ArrayList<Profil> liste = new ArrayList<Profil>();
			CallableStatement cs =  this.conn.prepareCall("call licpro.aeronautique.cherche_profil(?,?)");
			cs.setString(1, refer);
			cs.registerOutParameter(2, OracleTypes.CURSOR);
			cs.execute();
			ResultSet resultat = (ResultSet) cs.getObject(2);
			
			while (resultat.next())
			{
				String ref = resultat.getString("refer");
				String description = resultat.getString("description");
				int hauteur = resultat.getInt("hauteur");
				int longueur = resultat.getInt("longueur");
				int cdpx = resultat.getInt("cdpx");
				int cdpy = resultat.getInt("cdpy");
				double er = resultat.getDouble("er");
				double alpha = resultat.getDouble("alpha");
				double cz = resultat.getDouble("cz");
				double cx = resultat.getDouble("cx");
				Profil p = new Profil(ref,description,hauteur,longueur,cdpx,cdpy,er,alpha,cz,cx);
				liste.add(p);
				p.toString();
			}
			
			return liste;

		}
		
		catch (SQLException e)
		{
			throw new ErreurSQL(e.getErrorCode(), e.getMessage());
		}
	}
	
	/** Methode qui permet de créer un profil dans la table
	 * 
	 * @param refer la référence du profil à créer
	 * @param description la description du profil à créer
	 * @param hauteur la hauteur du profil à créer
	 * @param longueur la longueur du profil à créer
	 * @param cdpx le cdpx du profil à créer
	 * @param cdpy le cdpy du profil à créer
	 * @param er le er du profil à créer
	 * @param alpha l'alpha du profil à créer
	 * @param cz le cz du profil à créer
	 * @param cx le cx du profil à créer
	 * @throws ErreurSQL 
	 */
	public void creerProfil(String refer, String description, int hauteur, int longueur, int cdpx, int cdpy, double er, double alpha, double cz, double cx) throws ErreurSQL
	{
		try
		{
			CallableStatement cs =  this.conn.prepareCall("call licpro.aeronautique.creer_un_profil(?,?,?,?,?,?,?,?,?,?)");
			cs.setString(1, refer);
			cs.setString(2, description);
			cs.setInt(3, hauteur);
			cs.setInt(4, longueur);
			cs.setInt(5, cdpx);
			cs.setInt(6, cdpy);
			cs.setDouble(7, er);
			cs.setDouble(8, alpha);
			cs.setDouble(9, cz);
			cs.setDouble(10, cx);
			cs.execute();
			
		}
		
		catch (SQLException e)
		{
			throw new ErreurSQL(e.getErrorCode(), e.getMessage());
		}
	}
	
	/** Methode qui permet de supprimer un profil
	 * 
	 * @param refer la référence du profil à supprimer
	 * @throws ErreurSQL
	 */
	public void supprimerProfil(String refer) throws ErreurSQL
	{
		try
		{
			CallableStatement cs =  this.conn.prepareCall("call licpro.aeronautique.supprimer_un_profil(?)");
			cs.setString(1, refer);
			cs.execute();
		}
		
		catch (SQLException e)
		{
			throw new ErreurSQL(e.getErrorCode(), e.getMessage());
		}
	}
	
	/** Methode qui permet de récupérer la liste des profils à l'aide des meta-données
	 * 
	 */
	public ArrayList<Profil> getListeWithMetaData() throws ErreurSQL
	{
		try
		{
			ArrayList<Profil> liste = new ArrayList<Profil>();
			HashMap<String,String> champs = new HashMap<String,String>();
			Statement stmt = this.conn.createStatement();
			ResultSet resultat = stmt.executeQuery("SELECT * FROM licpro.profil");
			ResultSetMetaData rsmd= resultat.getMetaData();
			
			int nbcolonnes = rsmd.getColumnCount();
			
			for (int i=1; i<=nbcolonnes; i++)
			{
				String nomcol = rsmd.getColumnName(i);
				nomcol = nomcol.substring(0, 1) + nomcol.substring(1, nomcol.length()).toLowerCase();
				String type = rsmd.getColumnTypeName(i);
				
				if (type.equals("VARCHAR2"))
				{
					champs.put(nomcol, "String");
				}
				
				else if (type.equals("NUMBER"))
				{
					if (rsmd.getScale(i) > 0)
					{
						champs.put(nomcol, "Double");
					}
					
					else
					{
						champs.put(nomcol, "Int");
					}
				}
			}

			while (resultat.next())
			{
				Profil p = new Profil();
				Class<?> classse;
				for (String nomcol : champs.keySet())
				{
					classse = MetaDataUtils.getClassToInvoke(champs.get(nomcol));
					Object value = resultat.getClass().getMethod("get" + champs.get(nomcol), String.class).invoke(resultat, nomcol);
					
					p.getClass().getMethod("set" + nomcol, value.getClass()).invoke(p,value);
					
					liste.add(p);
				}
			}
			
			return liste;
		
		}
		
		catch (SQLException e)
		{
			throw new ErreurSQL(e.getErrorCode(), e.getMessage());
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			throw new ErreurSQL(-999, e.getMessage());
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			throw new ErreurSQL(-999, e.getMessage());
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			throw new ErreurSQL(-999, e.getMessage());
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			throw new ErreurSQL(-999, e.getMessage());
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			throw new ErreurSQL(-999, e.getMessage());
		}

	}
}
